#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠萝测试笔记
# blog:  https://www.cnblogs.com/poloyy/
# time: 2021/10/12 7:48 下午
# file: login_utils.py
"""
import datetime
import random
import string
from datetime import timedelta
from io import BytesIO
from typing import Any, Dict

from app.utils.redis_utils import my_redis
from captcha.image import ImageCaptcha
from fastapi import APIRouter, Depends, HTTPException, status, Form
from fastapi.responses import StreamingResponse
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.orm import Session

from app import crud, models, schemas
from app.api.deps import get_current_active_user, get_db
from app.config.setting import settings
from app.core.myenum import States
from app.core.security import create_access_token
from app.schemas import Token

router = APIRouter()


@router.post("/captcha.png")
async def get_captcha(uuid: str) -> Any:
    """
    ### 获取验证码图片，点击验证码可刷新验证码并重新发起一次该请求
    - :param uuid: 前端生成的 uuid，具备唯一性，如：09d33df4-3bd6-11ec-b82f-acde48001122
    """
    width, height = 180, 60
    generator = ImageCaptcha(width=width, height=height)
    random_str = "".join(random.sample(string.digits + string.ascii_letters, 5))
    img = generator.generate_image(random_str)
    generator.create_noise_dots(img, "#000000", 2, 40)
    generator.create_noise_curve(img, "#000000")
    out = BytesIO()
    img.save(out, "png")
    out.seek(0)
    my_redis.set(uuid, random_str.lower(), ex=settings.redis_port_expire_seconds)
    return StreamingResponse(out, media_type="image/png")


@router.post("/access_token", response_model=Token)
async def login_access_token(
    *,
    form_data: OAuth2PasswordRequestForm = Depends(),
    uuid: str = Form(..., description="前端传递的唯一uuid"),
    captcha: str = Form(..., description="验证码"),
    db: Session = Depends(get_db)
) -> Dict:
    """
    ### 登录获取 token,需要后面的请求头都带上这个请求返回的 access_token
    - 请求头格式：Authorization: Bearer {access_token}
    - :param form_data: form 表单数据（前端需要传 username、password），格式 form-data
    - :param uuid: 调用 captcha.png 时生成的 uuid
    - :param captcha: 验证码
    - :param db: 数据库对象（前端不需要传）
    - :return: token Model
    """
    username = form_data.username
    password = form_data.password
    # 验证用户名、密码
    user_data = crud.user.authenticate(db, username=username, password=password)
    if not user_data:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="用户名或密码不正确")

    if user_data.state == States.NO_ACTIVE:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="用户未激活")

    if user_data.is_delete == States.IS_DELETE:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="用户不存在")

    if not my_redis.get(uuid):
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="验证码已过期")

    if not my_redis.get(uuid) == captcha.lower():
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="验证码错误")

    # 验证通过，生成 jwt token
    access_token_expires = timedelta(minutes=settings.access_token_expire_minutes)
    access_token = create_access_token(user_data.id, expires_delta=access_token_expires)

    # 更新登录时间
    crud.user.update(
        db, db_obj=user_data, obj_in={"last_login_time": datetime.datetime.now()}
    )
    # 删除 redis 中的验证码
    my_redis.delete(uuid)

    return {"access_token": access_token, "token_type": "bearer"}


@router.post("/get_current_active_user", response_model=schemas.User)
async def get_current_active_user_(
    current_data: models.User = Depends(get_current_active_user),
) -> Any:
    """
    ### 获取当前 token 的活跃用户
    - :param current_data: 依赖项（前端不需要传）
    - :return: 用户个人信息
    """
    return current_data
